# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: xguo

import time
import coin.exchange.base.kr_rest.level_book as level_book_mdl
import coin.exchange.base.kr_rest.public_client_base as pubcb
import coin.exchange.bitstamp_v2.kr_rest.native_public_client as npubc
from coin.exchange.bitstamp_v2.kr_rest.constants import active_symbol_list
from coin.exchange.bitstamp_v2.kr_rest.product import BitstampProduct
from coin.exchange.base.kr_rest.rest_client_base import RestUpdate

from coin.proto.coin_market_query_pb2 import ProductTicker, ExchangeTicker


class BitstampFeedParser(object):
  @staticmethod
  def parse_native_ticker(update_msg, product):
    """ sample response message
    {
      "high": "10166.09",
      "last": "8504.14",
      "timestamp": "1517551984",
      "bid": "8490.00",
      "vwap": "9040.89",
      "volume": "31568.02056827",
      "low": "8455.00",
      "ask": "8504.14",
      "open": "9010.87"
    }"""
    return ProductTicker(ask=float(update_msg['ask']),
                         bid=float(update_msg['bid']),
                         last=float(update_msg['last']),
                         high=float(update_msg['high']),
                         low=float(update_msg['low']),
                         volume_24hr=float(update_msg['volume']),
                         exchange_timestamp=int(float(update_msg['timestamp']) * 1e+9),
                         native_symbol=product.native_symbol,
                         symbol=product.symbol)

  @staticmethod
  def parse_level_book(update_msg, product):
    """ sample response message
    {
      "timestamp": "1517551988",
      "bids": [
        [ "8490.00", "1.66617578" ],
        [ "8480.12", "0.23938081" ],
        [ "8480.11", "10.00000000" ],
        .....
      ],
      "asks": [
        [ "8504.14", "0.04870923" ],
        [ "8504.17", "0.96266723" ],
        [ "8509.99", "1.00000000" ],
        .....
      ]
    } """
    level_book = level_book_mdl.LevelBook(product)

    max_book_size = 20  # Bitstamp's book depth can reach to a few thousands.
    book_size = 0
    for elem in update_msg['asks']:
      level_elem = level_book_mdl.LevelElement(float(elem[0]), float(elem[1]), 0)
      level_book.add_ask(level_elem)
      book_size += 1
      if book_size >= max_book_size:
        break

    book_size = 0
    for elem in update_msg['bids']:
      level_elem = level_book_mdl.LevelElement(float(elem[0]), float(elem[1]), 0)
      level_book.add_bid(level_elem)
      book_size += 1
      if book_size >= max_book_size:
        break
    level_book.finalize()
    return level_book


class BitstampPublicClient(pubcb.PublicClientBase):
  def __init__(self, timeout=1):
    self.npubc = npubc.BitstampNativePublicClient(timeout=timeout)

  def query_ticker_impl(self, product):
    symbol = product.native_symbol
    update = self.npubc.get_ticker(symbol)
    update.msg = BitstampFeedParser.parse_native_ticker(update.msg, product)
    return update

  def query_exchange_ticker_impl(self):
    update_list = []
    req_time = time.time()
    for symbol in active_symbol_list:
      update = self.npubc.get_ticker(symbol)
      product = BitstampProduct.FromStr(symbol)
      update.msg = BitstampFeedParser.parse_native_ticker(update.msg, product)
      update_list.append(update)
    res_time = time.time()

    exchange_ticker = ExchangeTicker(
        exchange='Bitstamp',
        each_ticker=[update.msg for update in update_list],
    )
    return RestUpdate(req_time,
                      res_time,
                      exchange_ticker,
                      native_msg=[update.native_msg for udpate in update_list])

  def query_level_book_impl(self, product):
    symbol = product.native_symbol
    update = self.npubc.get_order_book(symbol)
    update.msg = BitstampFeedParser.parse_level_book(update.msg, product)
    return update
